#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "node.h"

Node* create_node(int nl, Node_type t, char* lex, void* att, int nbc, Node** children){

	int i;
	if ((nbc < 0) || (nbc > MAX_CHILDREN_NUMBER))
		exit(1);
	Node* newNode = create_leaf(nl, t, lex, att);
	newNode->numberOfChildren = nbc;
	newNode->children = children;
	return newNode;
}


Node* create_leaf(int nl, Node_type t, char* lex, void* att){
	
	if((t<299) || (t > MAX_TIPO))
		exit(1);
	Node* newNode = malloc(sizeof(Node));
	newNode->lineNumber = nl;

	if(lex == NULL)
		newNode->lexeme = NULL;
	else
	{
		newNode->lexeme = malloc(sizeof(char)*(strlen(lex) + 1));
        	strncpy(newNode->lexeme, lex, strlen(lex));
        	newNode->lexeme[strlen(lex)] = '\0';
	}

	newNode->type = t;
	newNode->attribute = att;
	newNode->numberOfChildren = 0;
	newNode->children=NULL;

	return newNode;		
}

int nb_of_children(Node* n) {
    if(n == NULL)
        exit(1);
    return n->numberOfChildren;
}


Node* child(Node* n, int i) {    
    if(n == NULL)
        exit(1);    
    if((i < 0) || (i >= n->numberOfChildren))
        exit(1);    
    return n->children[i];
}

int deep_free_node(Node* n) {
   int ret=0; 
   int i; 
   if(n == NULL)
       return 0;
   
   if(n->numberOfChildren > 0)
       for(i = 0; i < MAX_CHILDREN_NUMBER; i++)
           ret += deep_free_node(n->children[i]);
   
    free(n);
    return ret;
}


int height(Node* n) {
    int max = 0;
    int alt, i;
	
    if(n == NULL)
        return 0;
    
	
    for(i = 0; i < n->numberOfChildren; i++)
    {
        alt = height(n->children[i]);
        if(max < alt) 
            max = alt;
    }
	
    return 1 + max;
}

int pack_nodes(Node*** array_of_nodes, const int cur_size, Node* n) {
    if(array_of_nodes == NULL)
        exit(1);
    int i;
    
    if((cur_size < 0) || (cur_size >= MAX_CHILDREN_NUMBER))
        exit(1);
    
    if(cur_size == 0)
    {
        *array_of_nodes = malloc(sizeof(Node*) * MAX_CHILDREN_NUMBER);

        for(i = 0; i < MAX_CHILDREN_NUMBER; i++)
            (*array_of_nodes)[i] = NULL;
    }
	
    (*array_of_nodes)[cur_size] = n;
    return cur_size+1;
}

int is_leaf(Node* n)
{
	if(n == NULL)
	{
		printf("\nError in node.c - method is_leaf(Node* n) -\nMessage: Node received as parameter is NULL");
		exit(1);
	}
	else
	{
		if(n->numberOfChildren == 0)
		{
			return(1);
		}
		else
		{
			return(0);
		}
		
	}
	
	printf("\nError in node.c - method is_leaf(Node* n) -\nMessage: UNKNOWN error");
	exit(1);
}

void uncompile(FILE* outputFile, Node* n)
{
	int nodeIteratorIndex;
	
	if(n == NULL)
	{
		printf("\nError in node.c - method uncompile(FILE* outputFile, Node* n) -\nMessage: Node received as parameter is NULL");
		exit(1);
	}
	else
	{
		if(outputFile == NULL)
		{
			printf("\nError in node.c - method uncompile(FILE* outputFile, Node* n) -\nMessage: File Pointer received as parameter is NULL");
			exit(1);
		}
		else
		{
			if(!strcmp(n->lexeme, ";"))
			{
				fprintf(outputFile, "%s\n", n->lexeme);
			}
			else
			{
				fprintf(outputFile, "%s ", n->lexeme);
			}
	
			for(nodeIteratorIndex = 0; nodeIteratorIndex < n->numberOfChildren; nodeIteratorIndex++)
			{
				uncompile(outputFile, n->children[nodeIteratorIndex]);
			}
			
		}
	}
}


void print_tree(Node *n) {
    if(n == NULL){
        return;
    }
    int i;
    for(i=0; i< n->numberOfChildren; i++)
        print_tree(n->children[i]);

    if(n->numberOfChildren == 0){
      if (!strcmp(n->lexeme, ";")){
	  fprintf(stdout, "%s\n", n->lexeme);
      }	else {
	  fprintf(stdout, "%s ", n->lexeme);
      }
    }
}


